﻿using Microsoft.EntityFrameworkCore;
using mozhi.smarterp.AuthorCenter.EntityFrameworkCore;
using mozhi.smarterp.AuthorCenter.Enums;
using mozhi.smarterp.AuthorCenter.Permissions.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;

namespace mozhi.smarterp.AuthorCenter.Permissions
{
    public class PermissionGroupRepository : EfCoreRepository<AuthorCenterDbContext, PermissionGroup, Guid>, IPermissionGroupRepository
    {
        public PermissionGroupRepository(IDbContextProvider<AuthorCenterDbContext> dbContextProvider) : base(dbContextProvider)
        {
        }


        public override async Task<PermissionGroup> GetAsync(Guid id, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            var dbContext = await GetDbContextAsync();

            return await dbContext.Set<PermissionGroup>().Include(x=>x.Items).AsNoTracking().FirstOrDefaultAsync(x => x.Id == id);
        }

        public async Task<long> GetCountAsync(string filter = null, List<PermissionType> types = null, CancellationToken cancellationToken = default)
        {
            var dbContext = await GetDbContextAsync();

            return await dbContext.Set<PermissionGroup>().AsNoTracking()
                .WhereIf(types != null, x => types.Contains(x.Type))
                .LongCountAsync();
        }

        public async Task<PermissionItem> GetItemAsync(Guid id)
        {
            var dbContext = await GetDbContextAsync();

            return await dbContext.Set<PermissionItem>().AsNoTracking().FirstOrDefaultAsync(x => x.Id == id);
        }

        public async Task<PermissionItem> GetItemAsync(string code)
        {
            var dbContext = await GetDbContextAsync();

            return await dbContext.Set<PermissionItem>().AsNoTracking().FirstOrDefaultAsync(x => x.Code == code);
        }

        public async Task<List<PermissionItem>> GetItemListAsync(List<string> codes)
        {
            var dbContext = await GetDbContextAsync();

            return await dbContext.Set<PermissionItem>().AsNoTracking().Where(x => codes.Contains(x.Code)).ToListAsync();
        }

        public async Task<List<PermissionGroup>> GetListAsync(string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, string filter = null, bool includeDetails = false, List<PermissionType> types = null, CancellationToken cancellationToken = default)
        {
            var dbContext = await GetDbContextAsync();

            var query = includeDetails ? dbContext.Set<PermissionGroup>().Include(x => x.Items).AsNoTracking() : dbContext.Set<PermissionGroup>().AsNoTracking();

            return await query
                .WhereIf(types != null, x => types.Contains(x.Type))
                .ToListAsync();
        }

        public override async Task<PermissionGroup> UpdateAsync(PermissionGroup entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var dbContext = await GetDbContextAsync();

            var permissionGroup = await dbContext.Set<PermissionGroup>().Include(x=>x.Items).AsNoTracking().FirstOrDefaultAsync(x => x.Id == entity.Id);

            if (permissionGroup == null)
                return entity;

            dbContext.Set<PermissionGroup>().Update(entity);

            foreach(var item in entity.Items)
            {
                if(permissionGroup.Items.Any(x=>x.Id == item.Id))
                    dbContext.Set<PermissionItem>().Update(item);
                else
                    dbContext.Set<PermissionItem>().Add(item);
            }

            var removed = permissionGroup.Items.Where(x => !entity.Items.Select(y => y.Id).ToList().Contains(x.Id)).ToList();

            if (removed.Count>0)
            {
                foreach(var item in removed)
                {
                    dbContext.Set<PermissionItem>().Remove(item);
                }
            }


            if(autoSave)
                await dbContext.SaveChangesAsync();

            return entity;
        }
    }
}
